﻿<template>

    <div>
        <el-popover
                ref="expressionTipPopover"
                placement="bottom"
                width="300"
                trigger="manual"
                v-model="unitExpressionSuggest.tipVisible">

            <el-table :data="computeUnitList.filter(searchByRef)" highlight-current-row empty-text="无匹配数据"
                      :key="'computeunitsugguest'+modelInfo.id" @row-click="appendSuggest"
                      max-height="400">
                <el-table-column prop="ref" label="引用标识">
                </el-table-column>
                <el-table-column prop="name" label="名称">
                </el-table-column>
                <el-table-column prop="tag" label="标签">
                </el-table-column>
            </el-table>
        </el-popover>

        <el-dialog title="计算单元信息" :visible.sync="computeUnitDlgVisible" v-loading="unitUpdating" :close-on-click-modal="false">
            <el-form :model="computeUnit">
                <el-form-item label="单元名称" :label-width="formLabelWidth">
                    <el-input v-model="computeUnit.name" autocomplete="off" :disabled="editUnitMode"></el-input>
                </el-form-item>
                <el-form-item label="引用标识" :label-width="formLabelWidth">
                    <el-input v-model="computeUnit.ref" autocomplete="off" :disabled="editUnitMode">
                        <el-button v-if="modelEditable&&!editUnitMode" slot="append" @click="generateUnitRef">生成
                        </el-button>
                    </el-input>
                </el-form-item>
                <el-form-item label="标签"
                              :label-width="formLabelWidth">
                    <el-select
                            v-model="computeUnit.tag"
                            filterable
                            allow-create
                            default-first-option
                            placeholder="请选择或输入标签"
                            :disabled="!modelEditable">
                        <el-option
                                v-for="item in computeUnitTagList"
                                :key="item.value"
                                :label="item.text"
                                :value="item.value">
                        </el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="数据来源" :label-width="formLabelWidth" key="compute_datasource">
                    <meta-select v-model="computeUnit.type" type="compute-type" @change="changeComputeType" :disabled="!modelEditable"></meta-select>
                </el-form-item>
                <el-form-item v-if="computeUnit.type&&computeUnit.type!=''" label="数据"
                              :label-width="formLabelWidth">
                    <el-cascader v-if="computeUnit.type=='field'" :props="recordFieldCascaderProps"
                                 :options="inputTableList"
                                 v-model="computeUnit.data" :disabled="!modelEditable"></el-cascader>
                    <el-input type="textarea" :rows="4"
                              v-else-if="computeUnit.type=='expression'||computeUnit.type=='compute'"
                              v-model="computeUnit.data" @input="handleExpressionInput"
                              @blur="unitExpressionSuggest.tipVisible=false"
                              v-popover:expressionTipPopover
                              ref="expressionInput"
                              :disabled="!modelEditable"></el-input>

                    <el-select v-else-if="computeUnit.type=='project'" v-model="computeUnit.data"
                               placeholder="请选择" :disabled="!modelEditable">
                        <el-option
                                v-for="item in projectParamList"
                                :key="item.id"
                                :label="item.name"
                                :value="item.id">
                        </el-option>
                    </el-select>
                    <el-input type="text" v-else
                              v-model="computeUnit.data" :disabled="!modelEditable"></el-input>
                </el-form-item>
                <el-form-item
                        v-if="(computeUnit.type=='compute'||computeUnit.type=='expression')&&computeUnit.data&&computeUnit.data.length>0"
                        label="" :label-width="formLabelWidth">
                    <el-alert style="line-height:normal"
                              :title="replaceRef2Name(computeUnit.data)"
                              type="success"
                              :closable="false">
                    </el-alert>
                </el-form-item>
                <!--        <el-form-item label="排序值" :label-width="formLabelWidth">-->
                <!--          <el-input v-model="computeUnit.sort" autocomplete="off" :disabled="!modelEditable"></el-input>-->
                <!--        </el-form-item>-->
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="computeUnitDlgVisible = false">取 消</el-button>
                <el-button v-if="editUnitMode&&modelEditable" type="primary" @click="updateComputeUnit">修 改</el-button>
                <el-button v-else-if="modelEditable" type="primary" @click="createComputeUnit">创 建</el-button>
            </div>
        </el-dialog>

        <div style="float: right;margin-top:-40px;">
            <el-input size="small" placeholder="请输入搜索关键词" v-model="searchKey" width="300">
                <el-button slot="append" icon="el-icon-search"></el-button>
            </el-input>
        </div>
      <div :style="'overflow: scroll;height:'+pageHeight+'px'">
        <el-table
                :data="computeUnitList.filter(data => !searchKey || data.name.toLowerCase().includes(searchKey.toLowerCase()) || data.ref.toLowerCase().includes(searchKey.toLowerCase()))"
                border highlight-current-row style="margin-top: 0px;" empty-text="暂无数据"
                :key="'computeunittable'+modelInfo.id" v-loading="unitLoading" @row-click="updateComputeTree"
                :header-cell-style="{background:'#f5f7fa'}"
                @filter-change="updateFilterComputeTree" max-height="400">

            <el-table-column type="index" label="序号" align="center" width="50">
            </el-table-column>
            <el-table-column prop="ref" label="引用标识" header-align="center" show-overflow-tooltip>
            </el-table-column>
            <el-table-column prop="name" label="名称" header-align="center" show-overflow-tooltip>
            </el-table-column>
            <el-table-column prop="type" label="数据来源" header-align="center" :formatter="dataSourceShowFormatter"
                             width="100"
                             :filters="dataSourceFilterList"
                             :filter-method="filterDataSource"
                             filter-placement="bottom-end">
            </el-table-column>

            <el-table-column v-if="computeUnitTagList.length>0"
                             prop="tag" header-align="center"
                             label="标签"
                             :filters="computeUnitTagList"
                             :filter-method="filterTag"
                             filter-placement="bottom-end">
                <template slot-scope="scope">
                    <el-tag v-if="scope.row.tag&&scope.row.tag!=''"
                            type="primary"
                            disable-transitions>{{scope.row.tag}}
                    </el-tag>
                </template>
            </el-table-column>
            <!--      <el-table-column prop="sort" label="排序值" width="180" align="center">-->
            <!--      </el-table-column>-->
            <el-table-column prop="createTime" label="创建时间" width="180" align="center">
            </el-table-column>
            <el-table-column
                    align="right" width="180">
                <template slot="header">
                    <el-button
                            v-if="modelEditable"
                            type="primary"
                            size="small"
                            @click="openCreateUnitDlg">添加
                    </el-button>
                    <el-button
                            :loading="checkingModel"
                            v-if="modelEditable"
                            type="primary"
                            size="small"
                            @click="checkComputeModel">校验
                    </el-button>
                </template>
                <template slot-scope="scope">
                    <el-button
                            size="mini"
                            @click="openEditComputUnitDlg(scope.row)">
                        {{modelEditable?'编辑':'查看'}}
                    </el-button>
                    <el-button
                            v-if="modelEditable"
                            size="mini"
                            type="danger"
                            @click="deleteComputeUnit(scope.row.id)">删除
                    </el-button>
                </template>
            </el-table-column>
        </el-table>
        <template v-if="!unitLoading">
            <h1>计算模型结构 <span v-if="computeTreeData.nodeTree&&computeTreeData.nodeTree.length==1"> - {{computeTreeData.nodeTree[0].ref}}</span></h1>
            <el-tabs type="card" @tab-click="changeTab">
                <el-tab-pane label="计算依赖">
                    <el-tree
                            v-loading="treeLoading"
                            :data="computeTreeData.nodeTree"
                            node-key="id"
                            :props="computeTreeProps">
                        <span class="custom-tree-node" slot-scope="{ node, data }">
                            <span class="label" v-if="computeUnitMap[data.ref].type=='expression'||computeUnitMap[data.ref].type=='compute'">{{ computeUnitMap[data.ref].name }} = {{replaceRef2Name(computeUnitMap[data.ref].data)}}</span>
                            <span class="label" v-else>{{ computeUnitMap[data.ref].name }}</span>
                                        <span class="button-group">
                              <el-button
                                      size="mini"
                                      type="text"
                                      @click="openEditComputUnitDlg(computeUnitMap[data.ref])">
                                          {{modelEditable?'编辑':'查看'}}
                              </el-button>
                              <el-button
                                      v-if="modelEditable"
                                      type="text"
                                      size="mini"
                                      @click="deleteComputeUnit(computeUnitMap[data.ref].id)">
                                删除
                              </el-button>
                            </span>
                        </span>
                    </el-tree>
                </el-tab-pane>
                <el-tab-pane label="影响范围" v-if="computeTreeData&&computeTreeData.nodeTree&&computeTreeData.nodeTree.length==1" >
                    <el-tree
                            v-loading="treeLoading"
                            :data="computeEffectTree"
                            node-key="id"
                            :props="computeTreeProps">
                        <span class="custom-tree-node" slot-scope="{ node, data }">
                            <span class="label" v-if="computeUnitMap[data.ref].type=='expression'" v-html="data.displayText"></span>
                            <span class="label" v-else>{{ computeUnitMap[data.ref].name }}</span>
                                        <span class="button-group">
                              <el-button
                                      size="mini"
                                      type="text"
                                      @click="openEditComputUnitDlg(computeUnitMap[data.ref])">
                                          {{modelEditable?'编辑':'查看'}}
                              </el-button>
                              <el-button
                                      v-if="modelEditable"
                                      type="text"
                                      size="mini"
                                      @click="deleteComputeUnit(computeUnitMap[data.ref].id)">
                                删除
                              </el-button>
                            </span>
                        </span>
                    </el-tree>
                </el-tab-pane>

            </el-tabs>
        </template>
      </div>

    </div>

</template>

<script>
    import MetaSelect from "../../components/meta-select";
    export default {
        name: "ComputeModule",
      components: {MetaSelect},
      $$route: {
            path: 'compute-module',
            parentName: 'ModelInfo',
        },
        props:{
          modelInfo:{},
          pageHeight:{
            type:Number,
            default:500
          }
        },
        data() {
            return {
                projectParamList: [
                    {id: 'year', name: '当前评价年份'},
                    {id: 'yearStart', name: '评价起始年'},
                    {id: 'yearEnd', name: '评价结束年'},
                    {id: 'buildYearCount', name: '建设期年限'},
                ],
                unitLoading: false,
                treeLoading: false,
              unitUpdating:false,
                formLabelWidth: '120px',
                // newComputeUnit:{data:''},
                // editComputeUnit:{},
                computeUnit: {data: '', ref: ''},
                computeTreeData: {modelTree: [], nodeTree: []},
                computeEffectTree:[],
                unitTypeList: [],
                unitTypeMap: {},
                computeUnitList: [],
                computeTypeList: [],
                computeTypeMap: {},
                computeUnitDlgVisible: false,
                editUnitMode: false,
                inputTableList: [],
                modelEditable: false,
                recordFieldCascaderProps: {
                    label: 'name',
                    value: 'id',
                    emitPath: false,
                    children: 'fieldList',
                },
                computeTreeProps: {children: 'dependUnitList'},
                searchKey: null,
                unitExpressionSuggest: {
                    inputSearchKey: null,
                    tipVisible: false,
                },
                checkingModel: false,

            }
        },
        computed: {
            computeUnitTagList: function () {
                //获取计算单元所有分组
                let list = [];
                let map = {};
                for (let i = 0; i < this.computeUnitList.length; i++) {
                    let unit = this.computeUnitList[i];
                    if (!unit.tag || unit.tag == '') {
                        continue;
                    }
                    if (map[unit.tag]) {
                        continue;
                    }
                    map[unit.tag] = true;
                    list.push({text: unit.tag, value: unit.tag});
                }
                return list;
            },
            dataSourceFilterList: function () {
                let list = [];
                for (let i = 0; i < this.computeTypeList.length; i++) {
                    let item = this.computeTypeList[i];
                    list.push({text: item.name, value: item.id})
                }
                return list;
            },
            computeUnitMap: function () {
                let map = {};
                for (let unit of this.computeUnitList) {
                    map[unit.ref] = unit;
                }
                return map;
            }
        },
        created: function () {
            // const modelId = this.$route.params.id;
            const modelId = this.modelInfo.id;
            this.loadComputeUnitList(modelId);
            // this.loadModelInfo(modelId);
            this.modelEditable = this.modelInfo.state != 'publish';
            this.loadInputTableList(this.modelInfo.id);
            this.loadMetaList('compute-type',list => {
              this.computeTypeList = list;
              let map = {};
              for (let i = 0; i < this.computeTypeList.length; i++) {
                map[this.computeTypeList[i].id] = this.computeTypeList[i].name;
              }
              this.computeTypeMap = map;
            });
            // this.loadParamList(modelId);
        },
        methods: {
            // loadModelInfo: function (modelId) {
            //     this.$get("/model/" + modelId, {}, (response) => {
            //         this.modelInfo = response.data;
            //         this.modelEditable = this.modelInfo.state == 0;
            //         this.loadInputTableList(this.modelInfo.id);
            //     });
            // },
            loadInputTableList: function (modelId) {
                // this.unitLoading = true;
                this.$get("/table/fulldata?modelId=" + modelId, {}, (response) => {
                    this.inputTableList = response.data;
                }, () => {
                    // this.unitLoading = false;
                });
            },

            openCreateUnitDlg: function () {
                this.computeUnitDlgVisible = true;
                if (this.editUnitMode) {
                    this.computeUnit = {data: '', ref: ''};
                    this.editUnitMode = false;
                }

            },
            createComputeUnit: function () {
                this.computeUnit.modelId = this.modelInfo.id;
                this.$post("/compute/create", this.computeUnit, (response) => {
                    this.$message({
                        message: '创建成功',
                        type: 'success'
                    });
                    this.computeUnitDlgVisible = false;
                    this.loadComputeUnitList(this.modelInfo.id);
                });
            },
            updateComputeUnit: function () {

              this.unitUpdating = true;
                this.$post("/compute/update", this.computeUnit, (response) => {
                    this.$message({
                        message: '修改成功',
                        type: 'success'
                    });
                    this.computeUnitDlgVisible = false;
                    this.loadComputeUnitList(this.modelInfo.id);
                },()=>{
                  this.unitUpdating = false;
                });
            },
            deleteComputeUnit: function (id) {
                this.$get("/compute/delete?id=" + id, {}, (response) => {
                    this.$message({
                        message: '删除成功',
                        type: 'success'
                    });
                    this.loadComputeUnitList(this.modelInfo.id);
                });
            },
            loadComputeUnitList: function (id) {
                this.unitLoading = true;
                this.$get("/compute/data?modelId=" + id, {}, (response) => {
                    this.computeUnitList = response.data;
                    this.loadComputeUnitTree(id);
                }, () => {
                    this.unitLoading = false;
                });

            },
            loadComputeUnitTree: function (id) {
                this.treeLoading = true;
                this.$get("/compute/tree?modelId=" + id, {}, (response) => {
                    this.computeTreeData.modelTree = response.data;
                    // this.computeTreeData.nodeTree = response.data;
                }, () => {
                    this.treeLoading = false;
                });
            },

            loadParamList: function (modelId) {
                this.$get("/param/data?modelId=" + modelId, {}, (response) => {
                    let list = response.data;
                    for (let item of list) {
                        this.projectParamList.push({id: item.id, name: item.name});
                    }

                });
            },
            checkComputeModel: function () {
                this.checkingModel = true;
                this.$get("/compute/check?modelId=" + this.modelInfo.id, {}, (response) => {
                    this.checkingModel = false;
                    this.$message({
                        message: '校验通过',
                        type: 'success'
                    });
                }, response => {
                    if (response.code != 0) {
                        let reg = new RegExp(';', "g")
                        this.$alert(response.msg.replace(reg, '<br>'), '计算模型校验未通过', {
                            dangerouslyUseHTMLString: true
                        });
                    }
                    this.checkingModel = false;
                });
            },
            changeComputeType: function (data) {
                let validValue = false;
                if (data == 'project') {
                    for (let i = 0; i < this.projectParamList.length; i++) {
                        let param = this.projectParamList[i];
                        if (param.id == this.computeUnit.data) {
                            validValue = true;
                            break;
                        }
                    }
                    if (!validValue) {
                        this.computeUnit.data = null;
                    }
                    // this.computeUnit.keep = false;
                } else if (data == 'field') {
                    if (!validValue) {
                        this.computeUnit.data = null;
                    }
                } else {
                    if (data.keep) {
                        data.keep = false;
                    } else {
                        this.computeUnit.data = null;
                    }
                }
            },
            dataSourceShowFormatter: function (row, column, cellValue, index) {
                return this.computeTypeMap[cellValue];
            },
            filterTag: function (value, row) {
                return row.tag === value;
            },
            filterDataSource: function (value, row) {
                return row.type === value;
            },
            updateComputeTree: function (row, column, event) {
                function findNode(node, id) {
                    if (node.strongRef == false) {
                        return;
                    }
                    if (node.ref == id) {
                        return node;
                    }
                    if (!node.dependUnitList || node.dependUnitList == null) {
                        return;
                    }
                    let list = node.dependUnitList;
                    for (let i = 0; i < list.length; i++) {
                        let node = findNode(list[i], id);
                        if (node) {
                            return node;
                        }
                    }
                    return;
                }

                let treeData = this.computeTreeData.modelTree;
                for (let i = 0; i < treeData.length; i++) {
                    let node = findNode(treeData[i], row.ref);
                    if (node) {
                        this.computeTreeData.nodeTree = [node];

                        let effectList = [];
                        let regx = new RegExp("\\b"+node.ref+"\\b");
                        for(let unit of this.computeUnitList) {
                            if (!unit.type == 'expression' && !unit.type == 'compute') {
                                continue;
                            }
                            if(unit.data.match(regx)) {
                                let item = JSON.parse(JSON.stringify(unit));
                                item.dependUnitList = null;
                                item.displayText = this.computeUnitMap[unit.ref].name + ' = ' + this.replaceRef2Name(this.computeUnitMap[unit.ref].data,node.ref);
                                effectList.push(item);
                            }
                        }
                        this.computeEffectTree = effectList;

                        break;
                    }
                }





            },
            openEditComputUnitDlg: function (data) {
                this.computeUnit = JSON.parse(JSON.stringify(data));
                this.editUnitMode = true;
                this.computeUnitDlgVisible = true;
            },
            updateFilterComputeTree: function (data) {
                console.log(data);
            },
            handleExpressionInput: function (value) {
                let keywordReg = new RegExp('\\+|-|\\*|/|\\(|\\)|\\{|\\}|\\[|\\]', "g");

                let tmp = value.replace(keywordReg, ' ');
                tmp = tmp.split(' ');
                if (tmp.length <= 0) {
                    return;
                }

                this.unitExpressionSuggest.inputSearchKey = tmp[tmp.length - 1];
                this.unitExpressionSuggest.tipVisible = true;

            },
            searchByRef: function (data) {
                let value = this.unitExpressionSuggest.inputSearchKey;
                if (!value || value == null) {
                    this.unitExpressionSuggest.tipVisible = false;
                    return false;
                }
                return data.name.toLowerCase().includes(value.toLowerCase()) || data.ref.toLowerCase().includes(value.toLowerCase());
            },
            appendSuggest: function (row) {
                // if(this.computeUnit.type!='expression') {
                //     return;
                // }
                let reg = new RegExp('(.*)' + this.unitExpressionSuggest.inputSearchKey, "i");
                this.computeUnit.data = this.computeUnit.data.replace(reg, '$1' + row.ref);
                this.unitExpressionSuggest.inputSearchKey = null;
                this.$refs['expressionInput'].focus();
            },
            generateUnitRef: function () {
                if (!this.computeUnit.name || this.computeUnit.name == '') {
                    //单元名称为空，提示输入单元名称
                    this.$message({
                        message: '请先输入单元名称',
                        type: 'warning'
                    });
                    return;
                }
                // else if(this.computeUnit.ref&&this.computeUnit.ref.length>0) {
                //     this.$confirm('该操作将清除已输入的引用标识数据, 是否继续?', '提示', {
                //         confirmButtonText: '确定',
                //         cancelButtonText: '取消',
                //         type: 'warning'
                //     }).then(() => {
                //         this.computeUnit.ref = '';
                //         this.generateUnitRef();
                //     });
                //     return;
                // }
                this.$get("/compute/generateRef", {
                    name: this.computeUnit.name, modelId: this.modelInfo.id
                }, (response) => {
                    this.computeUnit.ref = response.data;
                });
            },
            replaceRef2Name: function (value,markRef) {
                let regList1 = [];
                regList1.push(new RegExp('(\\+|-|\\*|/|\\(|\\)|\\{|\\}|\\[|\\]|,)', "g"));
                regList1.push(new RegExp('(==)', "g"));
                regList1.push(new RegExp('(>=)', "g"));
                regList1.push(new RegExp('(<=)', "g"));
                regList1.push(new RegExp('(>)', "g"));
                regList1.push(new RegExp('(<)', "g"));
                let keywordReg3 = new RegExp('(#map)', "g");
                let keywordReg4 = new RegExp('(#list)', "g");

                let tmp = ' ' + value + ' ';
                for (let reg of regList1) {
                    tmp = tmp.replace(reg, ' $1 ');
                }
                tmp = tmp.replace(keywordReg3, ' (所有数据)');
                tmp = tmp.replace(keywordReg4, ' (所有数据)');
                let keywordReg5 = new RegExp('(< =)', "g");
                let keywordReg6 = new RegExp('(> =)', "g");
                tmp = tmp.replace(keywordReg5, '<=');
                tmp = tmp.replace(keywordReg6, '>=');
                for (let unit of this.computeUnitList) {
                    if (tmp.indexOf(unit.ref) < 0) {
                        continue;
                    }
                    let reg = new RegExp(' ' + unit.ref + ' ', "g");
                    let replaceStr = unit.name;
                    if(unit.ref==markRef) {
                        replaceStr = "<span style='color:red;'>"+replaceStr+"</span>";
                    }
                    tmp = tmp.replace(reg, replaceStr);
                }
                return tmp;
            },

            showCodeStruct: function (value) {
                let source = replaceRef2Name(value);
                let count = 0;
                let result = '';
                for (let i = 0; i < source.length; i++) {

                }
                return tmp;
            }

        },

    }
</script>
<style>
.custom-tree-node {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 14px;
  padding-right: 8px;
  overflow: hidden;
}

.custom-tree-node .label {
  overflow: hidden;
  flex-shrink: 1;
  text-overflow: ellipsis;
}

.custom-tree-node .button-group {
  flex-shrink: 0;
  flex-grow: 0;
}
</style>
